﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Controls;

namespace CjcPhotoPrint
{
	public class Crop : Transformation
	{
		public class CropContraint
		{
			public string Name { get; private set; }
			public double? AspectRatio { get; private set; }

			public CropContraint( string name, double? aspectRatio )
			{
				Name = name;
				AspectRatio = aspectRatio;
			}
		}

		private double aspectRatio = 1;
		private Rect bounds = new Rect( 0, 0, 1, 1 );
		private bool isLandscape = false;

		public Crop()
			: base( "Crop" )
		{
			Constraints = new BindingList<CropContraint>
			{
				new CropContraint( "4\" x 6\"", 4.0 / 6 ),
				new CropContraint( "8.5\" x 11\"", 8.5 / 11 ),
				new CropContraint( "Custom", null )
			};

			var view = CollectionViewSource.GetDefaultView( Constraints );
			view.MoveCurrentToLast();

			view.CurrentChanged += delegate { OnPropertyChanged( "AspectRatio" ); };
		}

		public BindingList<CropContraint> Constraints { get; private set; }

		public CropContraint Constraint
		{
			get { return CollectionViewSource.GetDefaultView( Constraints ).CurrentItem as CropContraint; }
		}

		public double? AspectRatio
		{
			get
			{
				var constraint = Constraint;

				return ( constraint != null && constraint.AspectRatio.HasValue )
					? (double?)( IsLandscape ? 1 / constraint.AspectRatio.Value : constraint.AspectRatio.Value )
					: null;
			}
		}

		public bool IsLandscape
		{
			get { return isLandscape; }
			set { isLandscape = value; OnPropertyChanged( "IsLandscape" ); }
		}

		public static double Constrain( double value )
		{
			return Math.Max( 0, Math.Min( 1, value ) );
		}

		public static Point Constrain( Point point )
		{
			return new Point( Constrain( point.X ), Constrain( point.Y ) );
		}

		public static Size Constrain( Size size )
		{
			return new Size( Constrain( size.Width ), Constrain( size.Height ) );
		}

		public static Rect Constrain( Rect rect )
		{
			var min = 0.0001;

			var tl = Constrain( rect.TopLeft );
			var br = Constrain( rect.BottomRight );

			return new Rect(
				tl,
				new Point( Math.Max( tl.X + min, br.X ), Math.Max( tl.Y + min, br.Y ) ) );
		}

		public Rect Bounds
		{
			get { return bounds; }
			set { bounds = Constrain( value ); OnPropertyChanged( "Bounds" ); }
		}

		public override Drawing GetDrawing( Drawing parent )
		{
			var minSize = 0.0001;
			var parentSize = RelativeSize( parent.Bounds.Width / parent.Bounds.Height );
			var boundsSize = RelativeSize( ( parentSize.Width * bounds.Width ) / ( parentSize.Height * bounds.Height ) );

			var transform = new TransformGroup();
			transform.Children.Add( new ScaleTransform( 1 / parentSize.Width, 1 / parentSize.Height ) );
			transform.Children.Add( new TranslateTransform( -bounds.Left, -bounds.Top ) );
			transform.Children.Add( new ScaleTransform( 1 / bounds.Width, 1 / bounds.Height ) );
			transform.Children.Add( new ScaleTransform( boundsSize.Width, boundsSize.Height ) );
/*
//			var parentSize = RelativeSize( parent.Bounds.Width / parent.Bounds.Height );
			var clipBounds = new Rect(
				bounds.Left * parent.Bounds.Width,
				bounds.Top * parent.Bounds.Height,
				bounds.Width * parent.Bounds.Width,
				bounds.Height * parent.Bounds.Height );
			var boundsSize = RelativeSize( clipBounds.Width / clipBounds.Height );

			var transform = new TransformGroup();
			transform.Children.Add( new TranslateTransform( -clipBounds.Left, -clipBounds.Top ) );
			transform.Children.Add( new ScaleTransform( 1 / Math.Max( minSize, bounds.Width ), 1 / Math.Max( minSize, bounds.Height ) ) );
*/
			var transformGroup = new DrawingGroup { Transform = transform };
			transformGroup.Children.Add( parent );

			var clipGroup = new DrawingGroup { ClipGeometry = new RectangleGeometry( new Rect( new Point(), boundsSize ) ) };
			clipGroup.Children.Add( transformGroup );
/*
			var parentSize = RelativeSize( parent.Bounds.Width / parent.Bounds.Height );
			var size = RelativeSize( Bounds.Width / Bounds.Height );
			var st = new ScaleTransform();
			var stretchGroup = new DrawingGroup { Transform = new ScaleTransform( 1 / parentSize.Width, 1 / parentSize.Height ) };
			stretchGroup.Children.Add( parent );

			var transform = new TransformGroup();
			transform.Children.Add( new TranslateTransform( -Bounds.Left, -Bounds.Top ) );
			transform.Children.Add( new ScaleTransform( 1 / Bounds.Width, 1 / Bounds.Height ) );
			transform.Children.Add( new ScaleTransform( parentSize.Width * size.Width, parentSize.Height * size.Height ) );

			var transformGroup = new DrawingGroup { Transform = transform };
			transformGroup.Children.Add( stretchGroup );

			var clipGroup = new DrawingGroup
			{
				ClipGeometry = new RectangleGeometry(
					new Rect(
						new Point(),
						new Size( bounds.Width / parent.Bounds.Width, bounds.Height / parent.Bounds.Height ) ) )
			};

			clipGroup.Children.Add( transformGroup );
*/
			return clipGroup;
		}
	}
}